package com.yuanzong.wuliu.common.utils.workbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
 *@author: zhao yue yue
 *@create: 2022-08-15 10:49
 */
public class ExcelHandler {
    /**
     * 批量处理梳理
     */
    public Integer batchNum;

    /**
     * 开始解析的行号，第一行时，startRow为0
     */
    public Integer startRow;

    /**
     * 封装的entity对象
     */
    public Class<?> entity;
    public Constructor<?> constructor;

    /**
     * 传入解析数据的service对象
     */
    public Consumer<List<T>> uploadService;

    /**
     * 接收解析对象值
     */
    public List<T> list = new ArrayList<>();

    public ExcelHandler(Consumer<List<T>> uploadService, Class<?> entity, Integer startRow, Integer batchNum) {
        this.uploadService = uploadService;
        this.entity = entity;
        this.startRow = startRow;
        this.batchNum = batchNum == null ? 1000 : batchNum;
    }

    /**
     * @param inputStream 数据流
     * @throws Exception
     */
    public void handlerData(InputStream inputStream) throws Exception {
        // 创建构造器
        this.constructor = entity.getDeclaredConstructor(new Class[]{List.class});
        // 创建表格对象
        XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
        //有多少个sheet
        int sheets = workbook.getNumberOfSheets();
        for (int i = 0; i < sheets; i++) {
            Sheet sheet = workbook.getSheetAt(i);
            //获取多少行
            int rows = sheet.getPhysicalNumberOfRows();
            //注意：第0为表头，第1行开始解析数据
            for (int currentRow = 0; currentRow < rows; currentRow++) {
                parseCellData(sheet, currentRow);
            }
        }
        // 所有数据解析完成后
        saveData(list);
    }

    /**
     * 一行解析完成后
     */
    private void endRow(List<Object> values, int currentRow) throws Exception {
        if (currentRow < startRow) {
            // 加载表头数据
            System.out.println("解析头部数据：" + values);
        } else {
            System.out.println("解析表格数据：" + values);
            T data = (T) constructor.newInstance(values);
            list.add(data);
        }

        if (list.size() >= batchNum) {
            // 回调接口，处理数据
            saveData(list);
        }
    }

    /**
     * 获取表格数据
     *
     * @param sheet
     * @param currentRow
     * @return
     */
    private void parseCellData(Sheet sheet, int currentRow) throws Exception {

        //获得第行号
        Row row = sheet.getRow(currentRow);

        // 解析正文数据
        List<Object> values = new ArrayList<>();
        for (int cellNum = 0; cellNum < row.getLastCellNum(); cellNum++) {
            Cell cell = row.getCell(cellNum);
            Object value = getCellValue(cell);
            values.add(value);
        }

        endRow(values, currentRow);
    }

    /**
     * 解析数据类型
     *
     * @param cell
     * @return
     */
    private Object getCellValue(Cell cell) {
        //1.获取到单元格的属性类型
        CellType cellType = cell.getCellType();
        //2.根据单元格数据类型获取数据
        Object value = null;
        switch (cellType) {
            case STRING:
                value = cell.getStringCellValue();
                break;
            case BOOLEAN:
                value = cell.getBooleanCellValue();
                break;
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    //日期格式
                    value = cell.getDateCellValue();
                } else {
                    //数字,poi解析的数值都是double类型
                    value = cell.getNumericCellValue();
                }
                break;
            case FORMULA:
                //公式
                value = cell.getCellFormula();
                break;
            default:
                break;
        }
        return value;
    }

    /**
     * 回调保存数据
     *
     * @param dataList
     */
    private void saveData(List<T> dataList) {
        if (dataList.size() > 0) {
            uploadService.accept(dataList);
            dataList.clear();
        }
    }
}
